package br.com.ac.fatureweb.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import br.com.ac.fatureweb.enums.EnumStatusCarga;
import br.com.ac.fatureweb.enums.Status;
import br.com.ac.fatureweb.integration.model.RoteiroVO;
import br.com.ac.fatureweb.model.Carga;
import br.com.ac.fatureweb.model.Equipamento;
import br.com.ac.fatureweb.model.ItemRoteiro;
import br.com.ac.fatureweb.model.Roteiro;
import br.com.ac.fatureweb.model.carga.Imovel;
import br.com.ac.fatureweb.utilitary.NgcDefaultBean;

@Local
@Named
@Stateless
public class NgcRoteiroBean extends NgcDefaultBean<Roteiro> {

	@PersistenceContext
	private EntityManager entityManager;

	@PostConstruct
	void inicialize() {
		setEm(entityManager);
	}

	@SuppressWarnings("unchecked")
	public List<Carga> getLstCarga(EnumStatusCarga status) {

		Query query = entityManager.createQuery("SELECT c FROM Carga c"
				+ " WHERE c.enumStatusCarga =:enumStatusCarga");

		query.setParameter("enumStatusCarga", status);

		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public void gerarRoteiro(Long id, Integer qtdLeiturista,
			Date dataFaturamento) {

		entityManager.setFlushMode(FlushModeType.COMMIT);

		Query query = entityManager.createQuery("SELECT i FROM Imovel i "
				+ " INNER JOIN i.carga car "
				+ " WHERE car.id =:id ORDER BY i.ordemRoteiro");

		query.setParameter("id", id);

		List<Imovel> lstImovel = query.getResultList();

		if (lstImovel != null && !lstImovel.isEmpty()) {

			// TODO Gerar o roteiro e associar os imóveis.
			Integer qtdImovelRoteiro = lstImovel.size() / qtdLeiturista;

			Integer qtdRoteiro = lstImovel.size() / qtdImovelRoteiro;

			int posicaoInicial = 0;

			for (int index = 1; index <= qtdRoteiro; index++) {

				posicaoInicial = gerarRoteiro(id, lstImovel, qtdImovelRoteiro,
						qtdRoteiro, posicaoInicial, index, dataFaturamento);
			}
		}

		Carga carga = entityManager.getReference(Carga.class, id);

		carga.setEnumStatusCarga(EnumStatusCarga.GERADO);

		entityManager.merge(carga);
	}

	/**
	 * 
	 * @param id
	 * @param lstImovel
	 * @param qtdImovelRoteiro
	 * @param qtdRoteiro
	 * @param posicaoInicial
	 * @param index
	 * @param dataFaturamento
	 * @return
	 */
	private int gerarRoteiro(Long id, List<Imovel> lstImovel,
			Integer qtdImovelRoteiro, Integer qtdRoteiro, int posicaoInicial,
			int index, Date dataFaturamento) {
		Roteiro roteiro = new Roteiro();

		roteiro.setCarga(new Carga(id));

		roteiro.setNumero(index);

		roteiro.setCompetencia(new Long(""
				+ lstImovel.iterator().next().getAno()
				+ lstImovel.iterator().next().getMes()));

		roteiro.setDataGeracao(new Date());

		roteiro.setDataFaturamento(dataFaturamento);

		roteiro.setStatus(Status.DISPONIVEL);

		roteiro.setLstItemRoteiro(new ArrayList<ItemRoteiro>());

		int posicaoFinal = posicaoInicial + qtdImovelRoteiro;

		if (index == qtdRoteiro) {
			posicaoFinal = lstImovel.size();
		}

		List<Imovel> subListImovel = gerarItemRoteiro(lstImovel,
				posicaoInicial, roteiro, posicaoFinal);

		roteiro.setQtdImovel(subListImovel.size());

		entityManager.persist(roteiro);

		posicaoInicial += qtdImovelRoteiro;
		return posicaoInicial;
	}

	/**
	 * 
	 * @param lstImovel
	 * @param posicaoInicial
	 * @param roteiro
	 * @param posicaoFinal
	 * @return
	 */
	private List<Imovel> gerarItemRoteiro(List<Imovel> lstImovel,
			int posicaoInicial, Roteiro roteiro, int posicaoFinal) {
		List<Imovel> subListImovel = new ArrayList<Imovel>(lstImovel.subList(
				posicaoInicial, posicaoFinal));

		int contador = 1;

		for (Imovel imovel : subListImovel) {

			ItemRoteiro itemRoteiro = new ItemRoteiro();

			itemRoteiro.setOrdem(contador);

			itemRoteiro.setImovel(imovel);

			itemRoteiro.setRoteiro(roteiro);

			roteiro.getLstItemRoteiro().add(itemRoteiro);

			contador++;
		}
		return subListImovel;
	}

	@SuppressWarnings("unchecked")
	public List<Equipamento> getLstEquipamento() {
		Query query = entityManager.createQuery("FROM Equipamento "
				+ " WHERE dataInativacao IS NULL");

		return query.getResultList();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.ac.fatureweb.utilitary.NgcDefaultBean#merge(java.lang.Object)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Roteiro merge(Roteiro entity) {

		Query query = entityManager
				.createQuery("SELECT rot.ordem FROM Roteiro rot "
						+ " INNER JOIN rot.equipamento eq "
						+ " WHERE eq.imei =:imei ORDER BY rot.ordem DESC ");

		query.setParameter("imei", entity.getEquipamento().getImei());

		query.setMaxResults(1);

		List<Integer> lstOrdem = query.getResultList();

		entity.setOrdem(1);

		if (lstOrdem != null && !lstOrdem.isEmpty()) {
			entity.setOrdem(lstOrdem.iterator().next() + 1);
		}

		return super.merge(entity);
	}

	public Roteiro getRoteiro(Long id) {
		Roteiro roteiro = entityManager.find(Roteiro.class, id);

		roteiro.getLstItemRoteiro().size();

		if (roteiro.getLstItemRoteiro() != null
				&& !roteiro.getLstItemRoteiro().isEmpty()) {
			for (ItemRoteiro itemRoteiro : roteiro.getLstItemRoteiro()) {
				itemRoteiro.getImovel().getId();
			}
		}

		return roteiro;
	}

	/**
	 * Buscar o roteiro com a menor ordem para execução das leituras. Procurar
	 * os roteiros que estão com status disponível.
	 * 
	 * @param imei
	 *            Identificador do equipamento.
	 * 
	 * @return Roteiro com a menor ordem encontrado para carga.
	 */
	@SuppressWarnings("unchecked")
	public RoteiroVO findRoteiro(String imei) {
		Query query = entityManager.createQuery("SELECT rot "
				+ " FROM Roteiro rot INNER JOIN rot.equipamento eq "
				+ " WHERE eq.imei =:imei AND rot.status =:status"
				+ " ORDER BY rot.ordem ASC ");

		query.setParameter("imei", imei);

		query.setParameter("status", Status.DISPONIVEL);

		query.setMaxResults(1);

		List<Roteiro> lstRoteiro = query.getResultList();

		if (lstRoteiro != null && !lstRoteiro.isEmpty()) {
			Roteiro roteiro = lstRoteiro.iterator().next();

			Calendar calendar = Calendar.getInstance(new Locale("pt", "BR"));

			calendar.setTime(roteiro.getDataGeracao());

			RoteiroVO roteiroVO = new RoteiroVO();

			roteiroVO.setId(roteiro.getId());
			roteiroVO.setNumero(roteiro.getNumero());
			roteiroVO.setOrdem(roteiro.getOrdem());
			roteiroVO.setCompetencia(roteiro.getCompetencia());
			roteiroVO.setDataGeracao(calendar.getTimeInMillis());
			roteiroVO.setQtdImovel(roteiro.getQtdImovel());

			calendar.setTime(roteiro.getDataFaturamento());
			roteiroVO.setDataFaturamento(calendar.getTimeInMillis());

			return roteiroVO;
		}

		return null;
	}
}
